package cc.rome753.wat;

import android.Manifest;
import android.content.pm.PackageManager;
import android.hardware.camera2.CameraCharacteristics;
import android.os.Bundle;
import android.util.Log;
import android.view.View;

import androidx.appcompat.app.AppCompatActivity;
import androidx.core.content.ContextCompat;

import org.webrtc.AudioSource;
import org.webrtc.AudioTrack;
import org.webrtc.Camera2Enumerator;
import org.webrtc.CapturerObserver;
import org.webrtc.EglBase;
import org.webrtc.MediaConstraints;
import org.webrtc.PeerConnectionFactory;
import org.webrtc.SurfaceTextureHelper;
import org.webrtc.SurfaceViewRenderer;
import org.webrtc.VideoCapturer;
import org.webrtc.VideoFrame;
import org.webrtc.VideoSource;
import org.webrtc.VideoTrack;

import java.util.Arrays;

public class MainActivity extends AppCompatActivity {
    private static final String TAG = MainActivity.class.getSimpleName();

    //region global variable
    PeerConnectionFactory.InitializationOptions initializationOptions;
    PeerConnectionFactory peerConnectionFactory;
    AudioSource audioSource;
    AudioTrack audioTrack;
    EglBase.Context eglBaseContext;
    //endregion

    //region front variable
    boolean frontFlag;
    VideoCapturer videoCapturerFront;
    VideoSource videoSourceFront;
    VideoTrack videoTrackFront;
    SurfaceViewRenderer svrLocalViewFront;
    SurfaceTextureHelper surfaceTextureHelperFront;
    //endregion

    //region back variable
    boolean backFlag;
    VideoCapturer videoCapturerBack;
    VideoSource videoSourceBack;
    VideoTrack videoTrackBack;
    SurfaceViewRenderer svrLocalviewBack;
    SurfaceTextureHelper surfaceTextureHelperBack;
    //endregion

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        Log.i(TAG, "onCreate()");
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        // create PeerConnectionFactory
        initializationOptions = PeerConnectionFactory.InitializationOptions.builder(this).createInitializationOptions();
        PeerConnectionFactory.initialize(initializationOptions);
        peerConnectionFactory = PeerConnectionFactory.builder().createPeerConnectionFactory();

        // create AudioSource
        audioSource = peerConnectionFactory.createAudioSource(new MediaConstraints());
        audioTrack = peerConnectionFactory.createAudioTrack("101", audioSource);

        eglBaseContext = EglBase.create().getEglBaseContext();
        surfaceTextureHelperFront = SurfaceTextureHelper.create("CaptureThreadFront", eglBaseContext);

//        eglBaseContextBack = EglBase.create().getEglBaseContext();
        surfaceTextureHelperBack = SurfaceTextureHelper.create("CaptureThreadBack", eglBaseContext);

        svrLocalViewFront = findViewById(R.id.svr_localView_front);
        svrLocalViewFront.setMirror(true);
        svrLocalViewFront.init(eglBaseContext, null);

        svrLocalviewBack = findViewById(R.id.svr_localView_back);
        svrLocalviewBack.setMirror(false);
        svrLocalviewBack.init(eglBaseContext, null);

        if (!PermissionUtil.isMediaPermissionsGranted(this)) {
            PermissionUtil.gotoSettings(this, true);
        }
    }

    @Override
    protected void onDestroy() {
        Log.i(TAG, "onDestroy()");
        super.onDestroy();
        releaseAll();
    }

    private VideoCapturer createCameraCapturer(int facing) {
        Camera2Enumerator enumerator = new Camera2Enumerator(this);
        final String[] deviceNames = enumerator.getDeviceNames();

        if (facing == CameraCharacteristics.LENS_FACING_FRONT) {
            // First, try to find front facing camera
            for (String deviceName : deviceNames) {
                if (enumerator.isFrontFacing(deviceName)) {
                    VideoCapturer videoCapturer = enumerator.createCapturer(deviceName, null);

                    if (videoCapturer != null) {
                        return videoCapturer;
                    }
                }
            }
        } else {
            // Front facing camera not found, try something else
            for (String deviceName : deviceNames) {
                if (!enumerator.isFrontFacing(deviceName)) {
                    VideoCapturer videoCapturer = enumerator.createCapturer(deviceName, null);

                    if (videoCapturer != null) {
                        return videoCapturer;
                    }
                }
            }
        }

        return null;
    }

    public void onclick(View view) {
        int id = view.getId();
        if (id == R.id.svr_localView_front) {
            if (frontFlag) {
                stopFront();
            } else {
                startFront();
            }
        } else if (id == R.id.svr_localView_back) {
            if (backFlag) {
                stopBack();
            } else {
                startBack();
            }
        }
    }

    private void startFront() {
        // create front VideoCapturer
        if (videoCapturerFront == null) {
            videoCapturerFront = createCameraCapturer(CameraCharacteristics.LENS_FACING_FRONT);
            videoCapturerFront.initialize(surfaceTextureHelperFront, getApplicationContext(), new CapturerObserver() {
                @Override
                public void onCapturerStarted(boolean b) {
                    Log.i(TAG, "front onCapturerStarted(), " + b);
                    frontFlag = b;
                    videoSourceFront.getCapturerObserver().onCapturerStarted(b);
                }

                @Override
                public void onCapturerStopped() {
                    Log.i(TAG, "front onCapturerStopped()");
                    videoSourceFront.getCapturerObserver().onCapturerStopped();
                    frontFlag = false;
                }

                @Override
                public void onFrameCaptured(VideoFrame videoFrame) {
//                Log.i(TAG, "front onFrameCaptured(), " + videoFrame);
                    videoSourceFront.getCapturerObserver().onFrameCaptured(videoFrame);
                }
            });
        }
        if (videoSourceFront == null) {
            videoSourceFront = peerConnectionFactory.createVideoSource(videoCapturerFront.isScreencast());
        }
        if (videoTrackFront == null) {
            // create VideoTrack
            videoTrackFront = peerConnectionFactory.createVideoTrack("100", videoSourceFront);
            // display in localView
            videoTrackFront.addSink(svrLocalViewFront);
        }
        videoCapturerFront.startCapture(480, 640, 30);
    }

    private void stopFront() {
        try {
            if (videoCapturerFront != null) {
                videoCapturerFront.stopCapture();
            }
        } catch (InterruptedException e) {
            Log.e(TAG, "", e);
        }
    }

    private void startBack() {
        if (videoCapturerBack == null) {
            // create back VideoCapturer
            videoCapturerBack = createCameraCapturer(CameraCharacteristics.LENS_FACING_BACK);
            videoCapturerBack.initialize(surfaceTextureHelperBack, getApplicationContext(), new CapturerObserver() {
                @Override
                public void onCapturerStarted(boolean b) {
                    Log.i(TAG, "back onCapturerStarted(), " + b);
                    backFlag = b;
                    videoSourceBack.getCapturerObserver().onCapturerStarted(b);
                }

                @Override
                public void onCapturerStopped() {
                    Log.i(TAG, "back onCapturerStopped()");
                    videoSourceBack.getCapturerObserver().onCapturerStopped();
                    backFlag = false;
                }

                @Override
                public void onFrameCaptured(VideoFrame videoFrame) {
//                Log.i(TAG, "back  onFrameCaptured(), " + videoFrame);
                    videoSourceBack.getCapturerObserver().onFrameCaptured(videoFrame);

                }
            });
        }
        if (videoSourceBack == null) {
            videoSourceBack = peerConnectionFactory.createVideoSource(videoCapturerBack.isScreencast());
        }
        if (videoTrackBack == null) {
            // create VideoTrack
            videoTrackBack = peerConnectionFactory.createVideoTrack("100", videoSourceBack);
            // display in localView
            videoTrackBack.addSink(svrLocalviewBack);
        }
        videoCapturerBack.startCapture(480, 640, 30);
    }

    private void stopBack() {
        try {
            if (videoCapturerBack != null) {
                videoCapturerBack.stopCapture();
            }
        } catch (InterruptedException e) {
            Log.e(TAG, "", e);
        }
    }

    private void releaseAll() {
        stopBack();
        stopFront();

        if (videoCapturerBack != null) {
            videoCapturerBack.dispose();
            videoCapturerBack = null;
        }
        if (videoTrackBack != null) {
            videoTrackBack.removeSink(svrLocalviewBack);
            videoTrackBack.dispose();
            videoTrackBack = null;
        }
        if (videoSourceBack != null) {
            videoSourceBack.dispose();
            videoSourceBack = null;
        }
        if (svrLocalviewBack != null) {
            svrLocalviewBack.release();
            svrLocalviewBack = null;
        }

        if (videoCapturerFront != null) {
            videoCapturerFront.dispose();
            videoCapturerFront = null;
        }
        if (videoTrackFront != null) {
            videoTrackFront.removeSink(svrLocalViewFront);
            videoTrackFront.dispose();
            videoTrackFront = null;
        }
        if (videoSourceFront != null) {
            videoSourceFront.dispose();
            videoSourceFront = null;
        }
        if (svrLocalViewFront != null) {
            svrLocalViewFront.release();
            svrLocalViewFront = null;
        }

        if (audioTrack != null) {
            audioTrack.dispose();
            audioTrack = null;
        }
        if (audioSource != null) {
            audioSource.dispose();
            audioSource = null;
        }

        if (surfaceTextureHelperFront != null) {
            surfaceTextureHelperFront.dispose();
            surfaceTextureHelperFront = null;
        }

        if (surfaceTextureHelperBack != null) {
            surfaceTextureHelperBack.dispose();
            surfaceTextureHelperBack = null;
        }

        if (peerConnectionFactory != null) {
            peerConnectionFactory.dispose();
            peerConnectionFactory = null;
        }
    }

}
